package com.ljx.interpreterMode;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * 解释器模式
 *
 * 定义：
 * 给定一个语言，定义它的文法表示，并定义一个解释器，这个解释器使用该标识来解释语言中的句子
 *
 * 优点：**
 * @ 易于改变和扩展文法。
 * 由于在解释器模式中使用类来表示语言的文法规则，因此可以通过继承等机制来改变或扩展文法。
 * 每一条文法规则都可以表示为一个类，因此可以方便地实现一个简单的语言。
 * @ 实现文法较为容易。
 * 在抽象语法树中每一个表达式节点类的实现方式都是相似的，这些类的代码编写都不会特别复杂。
 * @ 增加新的解释表达式较为方便。
 * 如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类，
 * 原有表达式类代码无须修改，符合 "开闭原则"。
 *
 * 缺点：**
 * @ 对于复杂文法难以维护。
 * 在解释器模式中，每一条规则至少需要定义一个类，因此如果一个语言包含太多文法规则，类的个数将会急剧增加，
 * 导致系统难以管理和维护。
 * @ 执行效率较低。
 * 由于在解释器模式中使用了大量的循环和递归调用，因此在解释较为复杂的句子时其速度很慢，而且代码的调试过程也比较麻烦
 *
 * 使用场景：
 * 当语言的文法较为简单，且执行效率不是关键问题时。
 * 当问题重复出现，且可以用一种简单的语言来进行表达时。
 * 当一个语言需要解释执行，并且语言中的句子可以表示为一个抽象语法树的时候
 *
 * @作者 LJX
 * @日期 2022/12/27 11:20
 */
public class InterpreterTest {

    public static void main(String[] args) {
        //创建环境对象
        Context context = new Context();

        //装填变量
        Variable a = new Variable("a");
        Variable b = new Variable("b");
        Variable c = new Variable("c");
        Variable d = new Variable("d");
        Variable e = new Variable("e");

        context.assign(a, new Value(1));
        context.assign(b, new Value(2));
        context.assign(c, new Value(3));
        context.assign(d, new Value(4));
        context.assign(e, new Value(5));

        //测试表达式  a + b + c + d - e
        AbstractExpression ae = new Plus(a, new Plus(b, new Plus(c, new Minus(d, e))));

        System.out.println(ae + "=" + ae.interpret(context));

    }

}

/**
 * 抽象表达式（Abstract Expression）角色
 */
abstract class AbstractExpression{

    public abstract Integer interpret(Context context);

}

/**
 * 终结符表达式角色 变量表达式
 */
@Data
class Variable extends AbstractExpression{

    String name;

    public Variable(String name) {
        this.name = name;
    }

    @Override
    public Integer interpret(Context context) {
        return context.getValue(this).getValue();
    }

    @Override
    public String toString() {
        return name;
    }
}

/**
 * 终结符表达式（Terminal  Expression）角色
 */
@Data
class Value extends AbstractExpression{

    private Integer value;

    public Value(Integer value) {
        this.value = value;
    }

    @Override
    public Integer interpret(Context context) {
        return value;
    }

    @Override
    public String toString() {
        return value.toString();
    }
}

/**
 * 非终结符表达式角色  加法表达式
 */
@Data
class Plus extends AbstractExpression{
    //加号左边表达式
    private AbstractExpression left;
    //加号右边表达式
    private AbstractExpression right;

    public Plus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public Integer interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}

/**
 * 非终结符表达式角色  减法表达式
 */
@Data
class Minus extends AbstractExpression{
    //减号左边表达式
    private AbstractExpression left;
    //减号右边表达式
    private AbstractExpression right;

    public Minus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public Integer interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

/**
 * 环境（Context）角色
 */
@Data
class Context{
    private Map<Variable, Value> map = new HashMap<>();

    public void assign(Variable variable, Value value){
        map.put(variable, value);
    }

    public Value getValue(Variable variable){
        return map.get(variable);
    }

}
